package au.com.darkside.XServer.Xext;

import android.util.Log;
import java.util.Hashtable;

import au.com.darkside.XServer.XServer;
import au.com.darkside.XServer.Client;
import au.com.darkside.XServer.InputOutput;
import au.com.darkside.XServer.Util;
import au.com.darkside.XServer.ErrorCode;

public class Sync
{
	private int syncMajor;
	private int syncMinor;
	private final Hashtable<String, SystemCounter>	_systemCounters;
	private final Hashtable<Integer, Counter>	_counters;
	
	public Sync()
	{
		syncMajor=-1;
		_systemCounters = new Hashtable<String, SystemCounter>();
		_systemCounters.put ("dummy", new SystemCounter (1,4, 0,"dummy"));
		_systemCounters.put ("SERVERTIME", new SystemCounter (3,6,7,"SERVERTIME"));
		_counters = new Hashtable<Integer, Counter>();
		
	}


	public void processRequest(
	XServer xServer, Client client,
	byte opcode, int arg,
	int bytesRemaining, int _sequenceNumber)
	throws java.io.IOException
	{
		InputOutput io=client.getInputOutput();
		switch(arg)
		{
			case Extensions.SYNC_INIT:
				if (bytesRemaining < 2) {
					io.readSkip (bytesRemaining);
					ErrorCode.write (client, ErrorCode.Length, opcode, 0);
				} else {
					syncMajor=io.readByte();
					syncMinor=io.readByte();
					bytesRemaining-=2;
					io.readSkip (bytesRemaining);
					synchronized(io)
					{
						Util.writeReplyHeader (client, arg);
						io.writeInt (0);	// Reply length.
						io.writeByte((byte) syncMajor);
						io.writeByte((byte) syncMinor);
						io.writePadBytes(22);
					}
					io.flush ();
					Log.i("XServExtensions","SYNC - Major:"+Integer.toString(syncMajor)+" Minor:"+Integer.toString(syncMinor));
				}
				break;
			case Extensions.SYNC_LIST:
				int n=_systemCounters.size();//number of counters
				int length=0;
				for(String key : _systemCounters.keySet())
				{
					Log.e("XGE",key+" "+Integer.toString(key.length()));
					int temp=(key.length()+2)%4;
					if(temp==0)
						temp=4;
					length+=14+key.length()+(4-temp);
				}
				int len=length%32;
				length/=32;
				if(len>0)
					length++;
				else
					len=32;
				length*=8;
				synchronized(io)
				{
					Util.writeReplyHeader (client, arg);
					io.writeInt (length);	// Reply length.
					io.writeInt (n);	// List length.
					io.writePadBytes(20); //unused
					for(SystemCounter count : _systemCounters.values())
					{
					/*   4         COUNTER                 counter
					 8         INT64                   resolution
					 2         n                       length of name in bytes
					 n         STRING8                 name
					 p                                 pad,p=pad(n+2)*/
						io.writeInt(count.COUNTER);
						io.writeInt(count.resLo);
						io.writeInt(count.resHi);
						io.writeShort(count.nameLength);
						io.writeBytes(count.name,0,count.name.length);
						int pad=(count.name.length+2)%4;
						if(pad==0)
							pad=4;
						io.writePadBytes(4-pad);
					}
					io.writePadBytes(32-(len));
				}
				io.flush();
				break;
			case Extensions.SYNC_CREATE:
				if (bytesRemaining != 12) {
					io.readSkip (bytesRemaining);
					ErrorCode.write (client, ErrorCode.Length, opcode, 0);
				} else {
					int ID=io.readInt();
					long initVal=io.readLong();
					bytesRemaining-=12;
					_counters.put(ID, new Counter(ID,initVal));
					Log.i("SYNC", "create counter - ID:"+Integer.toString(ID)+" Value:"+Long.toString(initVal));
				}
				break;
			case Extensions.SYNC_DESTROY:
				if (bytesRemaining != 4) {
					io.readSkip (bytesRemaining);
					ErrorCode.write (client, ErrorCode.Length, opcode, 0);
				} else {
					int ID=io.readInt();
					bytesRemaining-=4;
					Counter count=_counters.remove(ID);
					if(count!=null)
					{
						synchronized(io)
						{
							Util.writeReplyHeader (client, arg);
							io.writeInt(0);
							io.writeLong(count.getValue());
							io.writePadBytes(16);
						}
						io.flush();
					}
					else
					{
						ErrorCode.write (client, (byte)(Extensions.SYNC_ERROR_BASE+(byte)0), arg, opcode, ID);
					}
				}
				break;
			default:
				byte[] ba = new byte[bytesRemaining];

				io.readBytes(ba, 0, bytesRemaining);
				String str=new String(ba);
				Log.e("XServExtensions","SYNC unhandled minor opcode:"+Integer.toString(arg));
				Log.e("XServExtensions","DATA:"+str);
				break;
		}
	}}
